{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### --- Долги с прошлой лекции"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### C / C++  строки\n",
    "\n",
    "```c++\n",
    "//\n",
    "// С-строки\n",
    "//\n",
    "// функции стандартной библиотеки для работы со строками в стиле С\n",
    "// https://en.cppreference.com/w/cpp/string/byte\n",
    "\n",
    "// С-шная строка - это указатель на массив char, массив заканчивается нулевым символом.\n",
    "\n",
    "// Инициализация С-шной строки константными данными.\n",
    "// * Где лежит массив символов?\n",
    "// * Длина массива?\n",
    "const char* cname = \"cpushkin\";  // where? len?\n",
    "\n",
    "// Вывод С-шной строки на печать:\n",
    "std::cout << cname << std::endl;\n",
    "std::puts(cname);\n",
    "std::printf(\"%s\", cname);\n",
    "\n",
    "// Как скопировать строку?\n",
    "// Куда копировать?\n",
    "char* pcname = (char*)malloc(sizeof(char) * (strlen(cname) + 1));  // where? +1?\n",
    "std::strcpy(pcname, cname);\n",
    "std::puts(pcname);\n",
    "free(pcname);\n",
    "\n",
    "// Как сложить две строки:\n",
    "const char* greeting = \"Ai da \" + cname; // ! ERROR\n",
    "\n",
    "char *greeting = (char*)malloc(200);\n",
    "std::strcpy(\"Ai da \", greeting);\n",
    "std::strcpy(cpushkin, greeting + 6);\n",
    "std::puts(greeting);\n",
    "free(greeting);\n",
    "\n",
    "// Отметьте трудоёмкость простейших операций,\n",
    "// насколько легко допустить ошибку.\n",
    "\n",
    "\n",
    "//\n",
    "// C++ - строки\n",
    "//\n",
    "// класс стандартной строки:\n",
    "// https://en.cppreference.com/w/cpp/string/basic_string\n",
    "//\n",
    "// функции конвертации строк:\n",
    "// https://en.cppreference.com/w/cpp/string/basic_string/to_string\n",
    "\n",
    "// Инициализация С++-вой строки константными данными.\n",
    "// * Где лежит массив символов?\n",
    "// * Длина массива?\n",
    "std::string cppname = \"cpppushkin\";\n",
    "std::cout << cppname << std::endl;\n",
    "\n",
    "// Как скопировать строку?\n",
    "std::string name_copy = cppname;\n",
    "\n",
    "// Как сложить две строки:\n",
    "// 1\n",
    "std::string greeting = std::string(\"Ai da \") + cppname;\n",
    "// 2\n",
    "std::string greeting = \"Ai da \" + cppname;\n",
    "// 3\n",
    "std::string prep = \"Ai da\";\n",
    "std::string greeting = prep + \" \" + cppname; // OK\n",
    "        \n",
    "std::string* pcppname = &cppname; // что это?\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Ввод-вывод средствами С и C++"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задача**: посчитать сумму 500 000 целых чисел из потока ввода.\n",
    "\n",
    "Решим эту задачу средствами С и С++ и оценим различия в подходах."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Сгенерируем тестовые данные:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('input.txt', 'w') as f:\n",
    "    f.write(' '.join(['1'] * 500000))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Решение задачи с использованием средства ввода-вывода С:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <cstdio>\n",
    "\n",
    "int main()\n",
    "{\n",
    "    int sum = 0;\n",
    "    for (int i = 0; i < 500'000; ++i)\n",
    "    {\n",
    "        int x = 0;\n",
    "        std::scanf(\"%i\", &x);\n",
    "        sum += x;\n",
    "    }\n",
    "    std::printf(\"%i\\n\", sum);\n",
    "    return 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Со спецификацией форматов можно ознакомиться [здесь](https://en.cppreference.com/w/cpp/io/c/fprintf)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Решение задачи с использованием средства ввода-вывода С++:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <iostream>\n",
    "\n",
    "\n",
    "int main()\n",
    "{\n",
    "\tint sum = 0;\n",
    "\tfor (int i = 0; i < 500'000; ++i)\n",
    "\t{\n",
    "\t\tint x = 0;\n",
    "\t\tstd::cin >> x;\n",
    "\t\tsum += x;\n",
    "\t}\n",
    "\tstd::cout << sum << std::endl;\n",
    "\treturn 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Скомпилируем решения:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)\r\n",
      "Target: x86_64-pc-linux-gnu\r\n",
      "Thread model: posix\r\n",
      "InstalledDir: /usr/bin\r\n"
     ]
    }
   ],
   "source": [
    "!clang++ --version"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.08\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" clang++ -O3 main_c.cpp -o inout_c.exe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.28\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" clang++ -O3 main_cpp.cpp -o inout_cpp.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Проверим размеры исполняемых файлов"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-rwxrwxr-x 1 ivafanas ivafanas 8240 июл 29 22:52 inout_c.exe\r\n",
      "-rwxrwxr-x 1 ivafanas ivafanas 8880 июл 29 22:52 inout_cpp.exe\r\n"
     ]
    }
   ],
   "source": [
    "!ls -l *.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Зайдём на godbolt.org и посмотрим на причину, почему исполняемый файл для С++ - решения стал шире"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Запустим, проверим, какое работает быстрее"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.02\r\n",
      "500000\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" cat input.txt | ./inout_c.exe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.05\r\n",
      "500000\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" cat input.txt | ./inout_cpp.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вопросы для обсуждения:\n",
    "* Почему?\n",
    "* Всегда ли решение в стиле С работает быстрее?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Сравнение:\n",
    "\n",
    "С:\n",
    "* быстрая компиляция\n",
    "* быстрое выполнение\n",
    "* меньше размер исходного файла\n",
    "\n",
    "C++:\n",
    "* типобезопасно\n",
    "\n",
    "  ```c++\n",
    "  scanf(**\"%i\"**, &i);\n",
    "  ```\n",
    "\n",
    "\n",
    "* меньше ошибок при множественной записи / чтении:\n",
    "  ```c++\n",
    "  printf(\"%i %f %u\", i, z, n);\n",
    "  std::cout << i << ' ' << z << ' ' << n;\n",
    "  ```\n",
    "\n",
    "* меньше ошибок с адресной арифметикой\n",
    "\n",
    "  ```c++\n",
    "  scanf(\"%i\", **&**i);\n",
    "  ```\n",
    "\n",
    "\n",
    "<br />\n",
    "\n",
    "**Вывод**: если программа упирается в ввод-вывод - используем С - вариант, если нет - С++ - вариант."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Работа с командной строкой"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Общепринят формат передачи аргументов командной строки в программу, в котором аргументы делятся на:\n",
    "* позиционные\n",
    "* флажки\n",
    "* именованные со значением\n",
    "\n",
    "Пример программы `ls`, выводящей содержимое папки:\n",
    "\n",
    "```\n",
    "ls /usr/bin -a --human-readable --color=always\n",
    "ls -a --color always --human-readable /usr/bin\n",
    "```\n",
    "\n",
    "описание опций можно прочитать, набрав `ls --help`:\n",
    "\n",
    "```\n",
    "  -a, --all                  do not ignore entries starting with .\n",
    "  -h, --human-readable       with -l and/or -s, print human readable sizes\n",
    "                               (e.g., 1K 234M 2G)\n",
    "      --color[=WHEN]         colorize the output; WHEN can be 'always' (default\n",
    "                               if omitted), 'auto', or 'never'; more info below\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задача**: вывести аргументы командной строки, переданные консольной утилите"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <iostream>\n",
    "\n",
    "\n",
    "int main(int argc, char** argv)\n",
    "{\n",
    "\tstd::cout << \"command line arguments are:\" << std::endl;\n",
    "\tfor (int i = 0; i < argc; ++i)\n",
    "\t{\n",
    "\t\tstd::cout << \"    \" << i << \" -> \" << argv[i] << std::endl;\n",
    "\t}\n",
    "\treturn 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Скомпилируем"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "!clang++ -O3 main.cpp -o a.out"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Протестируем"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "command line arguments are:\r\n",
      "    0 -> ./a.out\r\n",
      "    1 -> /usr/bin\r\n",
      "    2 -> -a\r\n",
      "    3 -> --human-readable\r\n",
      "    4 -> --color=always\r\n"
     ]
    }
   ],
   "source": [
    "!./a.out /usr/bin -a --human-readable --color=always"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "command line arguments are:\r\n",
      "    0 -> ./a.out\r\n",
      "    1 -> /usr/bin\r\n",
      "    2 -> -a\r\n",
      "    3 -> --human-readable\r\n",
      "    4 -> --color\r\n",
      "    5 -> always\r\n"
     ]
    }
   ],
   "source": [
    "!./a.out /usr/bin -a --human-readable --color always"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "command line arguments are:\r\n",
      "    0 -> ./a.out\r\n",
      "    1 -> /usr/bin/my awesome app dir\r\n",
      "    2 -> -a\r\n",
      "    3 -> --human-readable\r\n",
      "    4 -> --color=always\r\n"
     ]
    }
   ],
   "source": [
    "!./a.out \"/usr/bin/my awesome app dir\" -a --human-readable --color=always"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Готовые решения:\n",
    "\n",
    "* C++, cross-platform [`boost::program_options`](https://www.boost.org/doc/libs/1_58_0/doc/html/program_options.html)\n",
    "* C, unix-only [`getopt`](https://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Лекция 2. Функции, пространства имён, заголовочные файлы, cmake, юнит-тестирование"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Функции, объявление и определение (declaration / definition)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Определение (definition) функции - описание её \"интерфейса\" (сигнатуры, возвращаемого типа и квалификаторов) И реализации."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "float abs(float x)\n",
    "{\n",
    "    if (x >= 0)\n",
    "        return x;\n",
    "    return -x;\n",
    "}\n",
    "\n",
    "float min_value(const std::vector<float>& items)\n",
    "{\n",
    "    float rv = items.front();\n",
    "    for (float x : items)\n",
    "        rv = std::min(rv, x);\n",
    "    return rv;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Замечание:\n",
    "* для поиска минимума, конечно же, используйте `std::min_element`\n",
    "* а для вычисления абсолютных величин функцию `abs` из `#include <cmath>`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Объявление (declaration) функции - описание её \"интерфейса\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "float abs(float x);\n",
    "\n",
    "float min_value(const std::vector<float>& items);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Если не прописано явно, у функции в программе может быть несколько объявлений, но не больше одного определения."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Вопрос__: что помещается в header-файл, что в cpp-файл?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Передача аргументов в функцию"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Передача по значению - создание копии аргумента"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "float min_value(std::vector<float> x);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Передача по ссылке - работа с аргументом"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "float min_value(std::vector<float>& x);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Передача по const-ссылке - работа с аргументом и запрет на модификацию"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "float min_value(const std::vector<float>& x);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Упражнение:** что здесь происходит с аргументами?\n",
    "\n",
    "```c++\n",
    "float sqr(const float x);\n",
    "\n",
    "float min_value(std::vector<float>* x);\n",
    "float min_value(const std::vector<float>* x);\n",
    "float min_value(std::vector<float>* const x);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Вопрос:** Когда лучше передавать по значению, а когда - по ссылке?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Возвращаемое значение"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Функция ничего не возвращает:\n",
    "\n",
    "```c++\n",
    "void say_hello(const std::string& name)\n",
    "{\n",
    "    std::cout << \"hello, \" << name;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Возврат результата через возвращаемое значение (предпочтительный вариант):\n",
    "\n",
    "```c++\n",
    "std::vector<std::string> make_team()\n",
    "{\n",
    "    return { \"Bifur\", \"Bofur\", \"Bombur\", \"Oin\",\n",
    "             \"Gloin\", \"Fili\", \"Nori\", \"Dori\",\n",
    "             \"Dwalin\", \"Ori\", \"Balin\", \"Kili\" };\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Возврат результата через аргумент (менее предпочтительный вариант в силу меньшей читаемости):\n",
    "\n",
    "```c++\n",
    "bool append_teamlead(Point3D location, std::vector<std::string>& team)\n",
    "{\n",
    "    if (is_inside(location, get_village(\"Shire\")))\n",
    "    {\n",
    "        team.push_back(\"Thorin\");\n",
    "        return true;\n",
    "    }\n",
    "    return false;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Сравните:\n",
    "    \n",
    "```c++\n",
    "// легко читается, что есть результат функции\n",
    "std::vector<std::string> team = make_team();\n",
    "\n",
    "// не очевидно, что результатом функции является\n",
    "// изменение второго аргумента, нужно лезть в\n",
    "// документацию или реализацию, чтобы понять\n",
    "// замысел автора\n",
    "append_teamlead(get_current_location(), team);\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Ошибки при работе с аргументами и возвращаемыми значениями"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string* find_dwarf(const std::vector<std::string>& team, const std::string& name)\n",
    "{\n",
    "    for (const std::string& dwarf : team)\n",
    "        if (dwarf == name)\n",
    "            return &dwarf;\n",
    "    return nullptr;\n",
    "}\n",
    "\n",
    "// usage 1\n",
    "std::vector<std::string> team = make_team();\n",
    "if (std::string* ptr = find_dwarf(team, \"Kuzya\"))\n",
    "    std::cout << *ptr;\n",
    "\n",
    "// usage 2\n",
    "if (std::string* ptr = find_dwarf(make_team(), \"Balin\"))\n",
    "    std::cout << *ptr;  // ???\n",
    "\n",
    "// usage 3\n",
    "if (std::string* ptr = find_dwarf({\"Ori\", \"Gloin\", \"Balin\"}, \"Balin\"))\n",
    "    std::cout << *ptr;  // ???\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Вопрос__: что будет напечатано программой ниже?\n",
    "\n",
    "Показать пример на godbolt.org на clang 8.0.0 с разными оптимизациями, чтобы наглядно продемонстрировать ub"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <iostream>\n",
    "#include <string>\n",
    "\n",
    "const std::string& f(const bool x,\n",
    "                     const std::string& s1,\n",
    "                     const std::string& s2)\n",
    "{\n",
    "    return x ? s1 : s2;\n",
    "}\n",
    "\n",
    "int main()\n",
    "{\n",
    "    const std::string& s = f(true, \"123\", \"12345\");\n",
    "    std::cout << s << endl;\n",
    "    return 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Значения аргументов по умолчанию"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Можно задавать значения аргументов по умолчанию:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string convert_to_string(int value, int base = 10);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string join_strings(const std::vector<std::string>& strings,\n",
    "                         const std::string& sep = \"\\n\");\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "использование:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string s1 = convert_to_string(42);    // 42\n",
    "std::string s2 = convert_to_string(42, 2); // 101010\n",
    "\n",
    "std::string song = join_strings({\"In the town where I was born\",\n",
    "                                 \"Lived a man who sailed to sea\",\n",
    "                                 \"And he told us of his life\",\n",
    "                                 \"In the land of submarines\",\n",
    "                                });\n",
    "                                 \n",
    "std::string sentence = join_strings({\"Nobody\",\n",
    "                                     \"expects\",\n",
    "                                     \"the\",\n",
    "                                     \"spanish\",\n",
    "                                     \"inquisition\",\n",
    "                                    },\n",
    "                                    \" \");\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Но такие аргументы должны быть последними:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string join_strings(const std::vector<std::string>& strings,\n",
    "                         const std::string& sep = \"\\n\",\n",
    "                         bool skip_empty_lines);  // compilation ERROR!\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string join_strings(const std::vector<std::string>& strings,\n",
    "                         const std::string& sep = \"\\n\",\n",
    "                         bool skip_empty_lines = false);  // OK\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Перегрузка функции"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://en.cppreference.com/book/intro/function_overloading"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Задача - реализовать конвертацию всего в строку. Желательно единообразно и чтобы: есть способ - компилируется и работает, нет способа - не компилируется."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string convert_to_string(int x);       // 1\n",
    "std::string convert_to_string(unsigned x);  // 2\n",
    "std::string convert_to_string(float x);     // 3\n",
    "\n",
    "std::cout << convert_to_string(5);    // 1\n",
    "std::cout << convert_to_string(5u);   // 2\n",
    "std::cout << convert_to_string(5.f);  // 3\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Для такого набора функций `convert_to_string` компилятор (clang 10.0) сгенерирует символы:\n",
    "* `_Z17convert_to_stringB5cxx11i`\n",
    "* `_Z17convert_to_stringB5cxx11j`\n",
    "* `_Z17convert_to_stringB5cxx11f`\n",
    "\n",
    "Т.е. тип аргумента - часть имени функции при компиляции."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Пространства имён и name mangling при компиляции"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://en.wikipedia.org/wiki/Name_mangling"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Пространства времён решают проблему, когда функция с одинаковым именем имеет две реализации в разных библиотеках.\n",
    "\n",
    "Рассмотрим сценарий, где вы с другом / подругой пишете свой личный Half Life 3, вы работаете над ИИ соперников, а компаньон - над анимациями объектов. И вам, и компаньону для отладки нужно вычленять из сцены интересующие объекты, каждому нужна функция:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "// EnemyAI.h\n",
    "// Получить объекты сцены, с которыми может взаимодействовать соперник (укрытия, маркеры огневых точек, цели ...)\n",
    "std::vector<Object*> collect_objects(const Scene& scene);\n",
    "\n",
    "// Animations.h\n",
    "// Получить анимируемые объекты сцены\n",
    "std::vector<Object*> collect_objects(const Scene& scene);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Такой код некорректен, т.к. для функции `collect_objects` нарушено ODR-правило (One Definition Rule).\n",
    "\n",
    "Вы можете поспорить с тем, что имена для функций из примера выбраны неудачно, но давайте остановимся на том факте, что иногда при выборе имён программисты между собой пересекаются."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "// EnemyAI.h\n",
    "namespace EnemyAI\n",
    "{\n",
    "  // Получить объекты сцены, с которыми может взаимодействовать соперник (укрытия, маркеры огневых точек, цели ...)\n",
    "  std::vector<Object*> collect_objects(const Scene& scene);\n",
    "}\n",
    "\n",
    "// Animations.h\n",
    "namespace Animations\n",
    "{\n",
    "  // Получить анимируемые объекты сцены\n",
    "  std::vector<Object*> collect_objects(const Scene& scene);\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Такой код слинкуется корректно, т.к. работает механизм name mangling во время компиляции.\n",
    "\n",
    "Компилятор (clang 10.0) сгенерирует такие имена символов для функций:\n",
    "\n",
    "* `_ZN7EnemyAI15collect_objectsERK5Scene`\n",
    "* `_ZN10Animations15collect_objectsERK5Scene`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Поиск функции и `using namespace`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Точные правила поиска:\n",
    "\n",
    "https://en.cppreference.com/w/cpp/language/lookup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "При компиляции куска кода:\n",
    "\n",
    "```c++\n",
    "namespace json_parser {\n",
    "namespace input_processing {\n",
    "\n",
    "int read_int(const std::string& s)\n",
    "{\n",
    "    if (avx_instructions_available())\n",
    "        return read_int_avx(s);\n",
    "    else\n",
    "        return read_int_default(s);\n",
    "}\n",
    "    \n",
    "}\n",
    "}\n",
    "```\n",
    "\n",
    "Компилятору нужно найти кандидатов для вызова `avx_instructions_available`, `read_int_avx` и `read_int_default`. Компилятор осуществляет их поиск в пространствах имён:\n",
    "* глобальное\n",
    "* `json_parser`\n",
    "* `json_parser::input_processing`\n",
    "* пространства имён аргументов функций (ничего для `avx_instructions_available`, `std` для `read_int_avx` и `read_int_default`)\n",
    "\n",
    "Если для какой-нибудь из функций находится либо более одного кандидата для вызова либо ни одного - ошибка компиляции. Кандидат должен быть и быть только один."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Замечание:** `using namespace X` - заполнить текущее пространство имён до закрывающей скобки именами из пространства X."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Пример 1:**\n",
    "\n",
    "Вызывающая программа:\n",
    "\n",
    "```c++\n",
    "#include \"json_parser.h\"\n",
    "\n",
    "int main()\n",
    "{\n",
    "    std::string s = \"123\";\n",
    "\n",
    "    // не скомпилируется, т.к. в глобальном пространстве имён нет функции read_int\n",
    "    std::cout << read_int(s);\n",
    "    \n",
    "    // скомпилируется\n",
    "    std::cout << json_parser::input_processing::read_int(s);\n",
    "    \n",
    "    // скомпилируется, т.к. глобальное пространство имён расширено\n",
    "    using namespace json_parser::input_processing;\n",
    "    std::cout << read_int(s);\n",
    "    \n",
    "    return 0;    \n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Пример 2:**\n",
    "\n",
    "```c++\n",
    "int main() {\n",
    "    std::cout << 1 << std::string(\"23\");\n",
    "    return 0;\n",
    "}\n",
    "```\n",
    "\n",
    "или\n",
    "\n",
    "```c++\n",
    "using namespace std; \n",
    "// имена из std доступны в глобальном пространстве имён до конца файла\n",
    "\n",
    "int main() {\n",
    "    cout << 1 << string(\"23\");\n",
    "    return 0;\n",
    "}\n",
    "```\n",
    "\n",
    "или\n",
    "\n",
    "```c++\n",
    "int main()\n",
    "{\n",
    "    using namespace std; \n",
    "    // имена из std доступны в глобальном пространстве имён до конца main\n",
    "\n",
    "    cout << 1 << string(\"23\");\n",
    "    return 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Рекомендации:**\n",
    "\n",
    "1. Никогда не пишите `using namespace` в `.h` - файлах (почему?)\n",
    "2. Ограничивайте область действия `using namespace` рационально.\n",
    "\n",
    "**Пример рациональности:** функция, считающая время выполнения другой функции (многословность `std::chrono`):\n",
    "\n",
    "```c++\n",
    "// без using namespace\n",
    "std::uint64_t get_execution_time_microseconds(const std::function<void>& f)\n",
    "{\n",
    "    const std::chrono::high_resolution_clock::time_point start_ts =\n",
    "        std::chrono::high_resolution_clock::now();\n",
    "    f();    \n",
    "    const std::chrono::high_resolution_clock::time_point final_ts =\n",
    "        std::chrono::high_resolution_clock::now();    \n",
    "    return std::chrono::duration_cast<std::chrono::microseconds>(final_ts - start_ts).count();\n",
    "}\n",
    "\n",
    "// с using namespace\n",
    "std::uint64_t get_execution_time_microseconds(const std::function<void>& f)\n",
    "{\n",
    "    using namespace std::chrono;    \n",
    "    const high_resolution_clock::time_point start_ts = high_resolution_clock::now();\n",
    "    f();    \n",
    "    const high_resolution_clock::time_point final_ts = high_resolution_clock::now();    \n",
    "    return duration_cast<microseconds>(final_ts - start_ts).count();\n",
    "}\n",
    "\n",
    "// с using namespace + auto\n",
    "std::uint64_t get_execution_time_microseconds(const std::function<void>& f)\n",
    "{\n",
    "    using namespace std::chrono;    \n",
    "    const auto start_ts = high_resolution_clock::now();\n",
    "    f();    \n",
    "    const auto final_ts = high_resolution_clock::now();    \n",
    "    return duration_cast<microseconds>(final_ts - start_ts).count();\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Чтение из файла"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтение из файла в стиле С"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <cstdio>\n",
    "\n",
    "int main()\n",
    "{\n",
    "\tFILE* f = std::fopen(\"input.txt\", \"r\");\n",
    "\tif (!f)\n",
    "\t{\n",
    "\t\tstd::puts(\"cannot open file input.txt\");\n",
    "\t\treturn 1;\n",
    "\t}\n",
    "\n",
    "\tint sum = 0;\n",
    "\tint x = 0;\n",
    "\twhile (std::fscanf(f, \"%i\", &x) != EOF)\n",
    "\t\tsum += x;\n",
    "\n",
    "\tstd::printf(\"sum = %i\\n\", sum);\n",
    "\n",
    "\tstd::fclose(f);\n",
    "\n",
    "\treturn 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтение из файла в стиле C++"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <fstream>\n",
    "#include <iostream>\n",
    "\n",
    "\n",
    "int main()\n",
    "{\n",
    "\tstd::ifstream ifs(\"input.txt\");\n",
    "\tif (!ifs)\n",
    "\t{\n",
    "\t\tstd::cerr << \"ERROR: cannot open file input.txt\" << std::endl;\n",
    "\t\treturn 1;\n",
    "\t}\n",
    "\n",
    "\tint sum = 0, x = 0;\n",
    "\twhile (ifs >> x)\n",
    "\t\tsum += x;\n",
    "\n",
    "\tstd::cout << sum << std::endl;\n",
    "\n",
    "\treturn 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтение из файла блоками"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <fstream>\n",
    "#include <iostream>\n",
    "#include <vector>\n",
    "\n",
    "\n",
    "int main()\n",
    "{\n",
    "\tstd::ifstream ifs(\"input.txt\");\n",
    "\tif (!ifs)\n",
    "\t{\n",
    "\t\tstd::cerr << \"ERROR: cannot open file\\n\";\n",
    "\t\treturn 1;\n",
    "\t}\n",
    "\n",
    "\tconst unsigned BUFSIZE = 4096; \n",
    "\tstd::vector<char> buffer(BUFSIZE);\n",
    "\n",
    "\twhile (true)\n",
    "\t{\n",
    "\t\tifs.read(&buffer[0], buffer.size());\n",
    "\t\tconst unsigned n = ifs.gcount();\n",
    "\t\tif (!n)\n",
    "\t\t\tbreak;\n",
    "\n",
    "\t\tstd::string s(&buffer[0], n);\n",
    "\t\tstd::cout << s;\n",
    "\t}\n",
    "\n",
    "\treturn 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### istream / ostream"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Возможно, вы заметили, в С++ работа с чтением из файла через механизм потоков очень похожа с вводом-выводом из консоли.\n",
    "\n",
    "Это не случайно. Класс, который отвечает за чтение из потока: `std::istream`.\n",
    "\n",
    "Чтение из потока выглядит так:\n",
    "\n",
    "```c++\n",
    "int x;\n",
    "std::cin >> x;\n",
    "```\n",
    "\n",
    "Класс `std::ifstream` наследуется от него. Файл представляется как поток данных. Чтение из файла:\n",
    "\n",
    "```c++\n",
    "std::ifstream ifs(\"input.txt\");\n",
    "int x;\n",
    "ifs >> x;\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Механизм потоков даёт возможность программисту дёшево абстрагироваться от источника данных (файл, поток ввода, память ...) и написать код, который будет работать с произвольным источником."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Пример:** Напишем функцию, которая читает `int` из потока:\n",
    "\n",
    "```c++\n",
    "int read_int(std::istream& is)\n",
    "{\n",
    "    int x;\n",
    "    is >> x;\n",
    "    return x;\n",
    "}\n",
    "```\n",
    "\n",
    "Вызывать эту функцию мы можем для любого потока:\n",
    "\n",
    "```c++\n",
    "int value1 = read_int(std::cin);  // чтение целого из потока stdin\n",
    "\n",
    "std::ifstream ifs(\"input.txt\");\n",
    "int value2 = read_int(ifs);       // чтение целого из файла\n",
    "\n",
    "std::stringstream ss(\"36\");\n",
    "int value3 = read_int(ss);        // чтение целого из памяти, представленной std::stringstream\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Юнит-тесты"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Контракты функции:\n",
    "  * предусловие (precondition / expect)\n",
    "  * постусловие (postcondition / ensure)\n",
    "  * инвариант (precondition + postcondition / invariant)\n",
    "\n",
    "\n",
    "Приведите примеры контрактов (exception-ы исключаем из рассмотрения, \"сейчас про них ничего не знаем\"):\n",
    "\n",
    "```c++\n",
    "double sqrt(double x);\n",
    "bool binary_search(int *arr, int n, int value);\n",
    "unsigned read_n(std::istream& is);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Типы функциональных тестов:\n",
    "* позитивный сценарий\n",
    "* негативный сценарий\n",
    "* граничные условия\n",
    "\n",
    "Приведите примеры тестов на функции `sqrt`, `binary_search`, `read_n`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Для упражнения напишем тесты на функцию, считающую длину ломаной"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "// polyline.h\n",
    "#pragma once\n",
    "#include <vector>\n",
    "\n",
    "struct Point\n",
    "{\n",
    "\tfloat x;\n",
    "\tfloat y;\n",
    "};\n",
    "\n",
    "float get_polyline_len(const std::vector<Point>& polyline);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "// polyline.cpp\n",
    "#include \"polyline.h\"\n",
    "#include <cmath>\n",
    "\n",
    "float get_polyline_len(const std::vector<Point>& polyline)\n",
    "{\n",
    "    float rv = 0;\n",
    "    for (int i = 1; i < polyline.size(); ++i)\n",
    "    {\n",
    "        const Point prev = polyline[i - 1];\n",
    "        const Point curr = polyline[i];\n",
    "        const float dx = curr.x - prev.x;\n",
    "        const float dy = curr.y - prev.y;\n",
    "        rv += std::sqrt(dx * dx + dy * dy);\n",
    "    }\n",
    "    return rv;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "// polyline_test.cpp\n",
    "#include \"polyline.h\"\n",
    "#include \"gtest/gtest.h\"\n",
    "\n",
    "TEST(get_polyline_len, empty_polyline)\n",
    "{\n",
    "\tstd::vector<Point> empty_poly;\n",
    "\tconst double len = get_polyline_len(empty_poly);\n",
    "\tEXPECT_EQ(0, len);\n",
    "}\n",
    "\n",
    "TEST(get_polyline_len, single_point_polyline)\n",
    "{\n",
    "\tstd::vector<Point> poly{{1,1}};\n",
    "\tconst double len = get_polyline_len(poly);\n",
    "\tEXPECT_EQ(0, len);\n",
    "}\n",
    "\n",
    "// ???\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Назначение header-файлов и cpp-файлов"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Файлы в С++-программах делятся на 2 типа: компилируемые и включаемые:\n",
    "    \n",
    "* _Компилируемые_ файлы (`file.cpp`) - файлы с текстом на языке С++, подаются на вход компилятору для генерации соответствующего объектного файла с машинными интсрукциями (`file.o`)\n",
    "* _Включаемые_ файлы (`file.h`) - файлы с текстом на языке С++, не являются конечной целью компиляции, их содержимое копируется в `cpp`-файлы при их компиляции через директиву `#include`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Пример:** "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Напишем программу, по целому числу `n` считающую $(1 + 1/n)^n$.\n",
    "\n",
    "Программа будет состоять из трёх файлов:\n",
    "* `exp.cpp` - определение (definition) функции расчёта\n",
    "* `exp.h` - декларация функции расчёта\n",
    "* `main.cpp` - определение (definition) `main`\n",
    "* `test_exp.cpp` - тесты\n",
    "\n",
    "_Подробно объяснить программу_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Файл `exp.cpp`:\n",
    "\n",
    "```c++\n",
    "#include <cmath>\n",
    "\n",
    "double approximate_exp(const unsigned int n)\n",
    "{\n",
    "    if (n == 0)\n",
    "        return 1.0;\n",
    "    \n",
    "    return std::pow(1.0 + 1.0 / n, n);\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Файл `exp.h`:\n",
    "\n",
    "```c++\n",
    "#pragma once\n",
    "\n",
    "double approximate_exp(const unsigned int n);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Файл `main.cpp`:\n",
    "\n",
    "```c++\n",
    "#include \"exp.h\" // <---\n",
    "#include <iostream>\n",
    "\n",
    "int main()\n",
    "{\n",
    "    unsigned n = 0;\n",
    "    std::cin >> n;\n",
    "    \n",
    "    std::cout << approximate_exp(n);    \n",
    "    return 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Файл `test_exp.cpp`:\n",
    "\n",
    "```c++\n",
    "#include \"exp.h\"  // <---\n",
    "#include <gtest/gtest.h>\n",
    "\n",
    "TEST(approximate_exp, zero)\n",
    "{\n",
    "    EXPECT_FLOAT_NEAR(approximate_exp(0), 1.0, 1e-3);\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### CMake-обвязка над C++ - проектами"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Проштудировать содержимое `lab1_stub`, не забыть рассказать про схему компиляции."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Скрипт сборки:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-- The C compiler identification is GNU 7.5.0\n",
      "-- The CXX compiler identification is GNU 7.5.0\n",
      "-- Detecting C compiler ABI info\n",
      "-- Detecting C compiler ABI info - done\n",
      "-- Check for working C compiler: /usr/bin/cc - skipped\n",
      "-- Detecting C compile features\n",
      "-- Detecting C compile features - done\n",
      "-- Detecting CXX compiler ABI info\n",
      "-- Detecting CXX compiler ABI info - done\n",
      "-- Check for working CXX compiler: /usr/bin/c++ - skipped\n",
      "-- Detecting CXX compile features\n",
      "-- Detecting CXX compile features - done\n",
      "-- Configuring done\n",
      "-- Generating done\n",
      "-- Build files have been written to: /home/ivafanas/Documents/cpp_shad_students/2021/sem1/lecture_2_functions_namespace_cmake_unit_tests/build/googletest-download\n",
      "Scanning dependencies of target googletest\n",
      "[ 11%] Creating directories for 'googletest'\n",
      "[ 22%] Performing download step (git clone) for 'googletest'\n",
      "Cloning into 'googletest-src'...\n",
      "Already on 'master'\n",
      "Your branch is up to date with 'origin/master'.\n",
      "[ 33%] Performing update step for 'googletest'\n",
      "[ 44%] No patch step for 'googletest'\n",
      "[ 55%] No configure step for 'googletest'\n",
      "[ 66%] No build step for 'googletest'\n",
      "[ 77%] No install step for 'googletest'\n",
      "[ 88%] No test step for 'googletest'\n",
      "[100%] Completed 'googletest'\n",
      "[100%] Built target googletest\n",
      "-- Found Python: /usr/bin/python3.6 (found version \"3.6.9\") found components: Interpreter \n",
      "-- Looking for pthread.h\n",
      "-- Looking for pthread.h - found\n",
      "-- Performing Test CMAKE_HAVE_LIBC_PTHREAD\n",
      "-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed\n",
      "-- Looking for pthread_create in pthreads\n",
      "-- Looking for pthread_create in pthreads - not found\n",
      "-- Looking for pthread_create in pthread\n",
      "-- Looking for pthread_create in pthread - found\n",
      "-- Found Threads: TRUE  \n",
      "-- Configuring done\n",
      "-- Generating done\n",
      "-- Build files have been written to: /home/ivafanas/Documents/cpp_shad_students/2021/sem1/lecture_2_functions_namespace_cmake_unit_tests/build\n",
      "\u001b[35m\u001b[1mScanning dependencies of target hashlib\u001b[0m\n",
      "[  9%] \u001b[32mBuilding CXX object CMakeFiles/hashlib.dir/src/hash.cpp.o\u001b[0m\n",
      "[ 18%] \u001b[32m\u001b[1mLinking CXX static library libhashlib.a\u001b[0m\n",
      "[ 18%] Built target hashlib\n",
      "\u001b[35m\u001b[1mScanning dependencies of target hash\u001b[0m\n",
      "[ 27%] \u001b[32mBuilding CXX object CMakeFiles/hash.dir/src/main.cpp.o\u001b[0m\n",
      "[ 36%] \u001b[32m\u001b[1mLinking CXX executable hash\u001b[0m\n",
      "[ 36%] Built target hash\n",
      "\u001b[35m\u001b[1mScanning dependencies of target gtest\u001b[0m\n",
      "[ 45%] \u001b[32mBuilding CXX object googletest-build/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o\u001b[0m\n",
      "[ 54%] \u001b[32m\u001b[1mLinking CXX static library ../../lib/libgtest.a\u001b[0m\n",
      "[ 54%] Built target gtest\n",
      "\u001b[35m\u001b[1mScanning dependencies of target gtest_main\u001b[0m\n",
      "[ 63%] \u001b[32mBuilding CXX object googletest-build/googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o\u001b[0m\n",
      "[ 72%] \u001b[32m\u001b[1mLinking CXX static library ../../lib/libgtest_main.a\u001b[0m\n",
      "[ 72%] Built target gtest_main\n",
      "\u001b[35m\u001b[1mScanning dependencies of target hash_unittests\u001b[0m\n",
      "[ 81%] \u001b[32mBuilding CXX object CMakeFiles/hash_unittests.dir/src/tests/main.cpp.o\u001b[0m\n",
      "[ 90%] \u001b[32mBuilding CXX object CMakeFiles/hash_unittests.dir/src/tests/hash_unittest.cpp.o\u001b[0m\n",
      "[100%] \u001b[32m\u001b[1mLinking CXX executable hash_unittests\u001b[0m\n",
      "[100%] Built target hash_unittests\n"
     ]
    }
   ],
   "source": [
    "!rm -rf build && mkdir build && cd build && cmake ../../lab1_stub/hasher && cmake --build ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Содержимое папки build:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "bin\t\tcmake_install.cmake  googletest-src  lib\r\n",
      "CMakeCache.txt\tgoogletest-build     hash\t     libhashlib.a\r\n",
      "CMakeFiles\tgoogletest-download  hash_unittests  Makefile\r\n"
     ]
    }
   ],
   "source": [
    "!ls build"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Прогоним тесты:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0;32m[==========] \u001b[mRunning 3 tests from 1 test suite.\r\n",
      "\u001b[0;32m[----------] \u001b[mGlobal test environment set-up.\r\n",
      "\u001b[0;32m[----------] \u001b[m3 tests from function1\r\n",
      "\u001b[0;32m[ RUN      ] \u001b[mfunction1.scenario1\r\n",
      "\u001b[0;32m[       OK ] \u001b[mfunction1.scenario1 (0 ms)\r\n",
      "\u001b[0;32m[ RUN      ] \u001b[mfunction1.scenario2\r\n",
      "\u001b[0;32m[       OK ] \u001b[mfunction1.scenario2 (0 ms)\r\n",
      "\u001b[0;32m[ RUN      ] \u001b[mfunction1.scenario3\r\n",
      "/home/ivafanas/Documents/cpp_shad_students/2021/sem1/lab1_stub/hasher/src/tests/hash_unittest.cpp:17: Failure\r\n",
      "Expected equality of these values:\r\n",
      "  1\r\n",
      "  2\r\n",
      "\u001b[0;31m[  FAILED  ] \u001b[mfunction1.scenario3 (0 ms)\r\n",
      "\u001b[0;32m[----------] \u001b[m3 tests from function1 (0 ms total)\r\n",
      "\r\n",
      "\u001b[0;32m[----------] \u001b[mGlobal test environment tear-down\r\n",
      "\u001b[0;32m[==========] \u001b[m3 tests from 1 test suite ran. (0 ms total)\r\n",
      "\u001b[0;32m[  PASSED  ] \u001b[m2 tests.\r\n",
      "\u001b[0;31m[  FAILED  ] \u001b[m1 test, listed below:\r\n",
      "\u001b[0;31m[  FAILED  ] \u001b[mfunction1.scenario3\r\n",
      "\r\n",
      " 1 FAILED TEST\r\n"
     ]
    }
   ],
   "source": [
    "!build/hash_unittests"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Выдать первое домашнее задание если ещё не**"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
